package com.yanqu.road.server.channelserver.manager.activity.entername.rank;

import com.yanqu.road.pb.cross3.activity.XRankProto;
import com.yanqu.road.server.channelserver.manager.activity.ChannelActivityInfoMgr;
import com.yanqu.road.server.channelserver.manager.activity.entername.ChannelEnterNameRankMgr;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;

public class EnterNameRankModel {

    private int activityId;
    private int conditionType;
    //pk 分组（包含活动配置的两个或者多个分组）
    private int matchGroupId;
    private int rankNum = 200;
    private Comparator<EnterNameRank> rankSort = new EnterNameRankSort();

    //更新msg 频率
    private long lastChangeTime = System.currentTimeMillis();
    private int changeNum = 0;

    // 榜单不入库
    private LinkedList<EnterNameRank> rankList = new LinkedList<>();

    private int rankCapacity;

    //用于取瞬时排名
    private XRankProto.XUserRankListMsg listMsg;

    private boolean save;

    public EnterNameRankModel(int activityId, int conditionType, int matchGroupId) {
        this.activityId = activityId;
        this.conditionType = conditionType;
        this.matchGroupId = matchGroupId;
        setMaxRank(ChannelActivityInfoMgr.getChannelActivityMaxRank(activityId, conditionType));
    }

    public EnterNameRankModel(int activityId, int conditionType, int matchGroupId, int rankNum) {
        this.activityId = activityId;
        this.conditionType = conditionType;
        this.matchGroupId = matchGroupId;
        setMaxRank(rankNum);
    }

    public EnterNameRankModel(int activityId, int conditionType, int matchGroupId, int rankNum, Comparator<EnterNameRank> rankSort) {
        this.activityId = activityId;
        this.conditionType = conditionType;
        this.matchGroupId = matchGroupId;
        this.rankSort = rankSort;
        setMaxRank(rankNum);
    }

    private int calcRankCapacity(int maxRank) {
        return maxRank + 20;
    }

    public void setMaxRank(int maxRank) {
        this.rankNum = maxRank;
        this.rankCapacity = calcRankCapacity(maxRank);
    }

    public void rankChange(EnterNameRank rank) {
        boolean isChange = false;
        synchronized (this) {
            int size = rankList.size();
            EnterNameRank old = getMyRankInfo(rank.getUserId());
            if(null != old){
                if(rank.getUserBaseInfo() != null){
                    old.setUserBaseInfo(rank.getUserBaseInfo());
                }
                if(0 != old.getValue().compareTo(rank.getValue())){
                    old.setLastUpdateTime(rank.getLastUpdateTime());
                }
                old.setValue(rank.getValue());
                old.setParam(rank.getParam());
                isChange = true;
            }else {
                if (size < rankCapacity) {
                    EnterNameRank newRank = rank.clone();
                    rankList.add(newRank);
                    isChange = true;
                } else if (rankSort.compare(rank, rankList.getLast()) < 0) {
                    EnterNameRank newRank = rank.clone();
                    rankList.removeLast();
                    rankList.add(newRank);
                    isChange = true;
                }
            }
            if(isChange) {
                rankList.sort(rankSort);
                changeNum++;
                if(changeNum >= 5 && System.currentTimeMillis() - lastChangeTime > 5 * 1000){
                    lastChangeTime = System.currentTimeMillis();
                    changeNum = 0;
                    initListMsg();
                }
            }
        }
    }

    public void setRankList(LinkedList<EnterNameRank> userRankList) {
        synchronized (this) {
            rankList = new LinkedList<>(userRankList);
            rankList.sort(rankSort);
            while (rankList.size() > rankCapacity){
                rankList.removeLast();
            }
            initListMsg();
        }
    }

    public LinkedList<EnterNameRank> getRankList() {
        LinkedList<EnterNameRank> tempList = new LinkedList<>();
        for (EnterNameRank rank : new ArrayList<>(rankList)) {
            tempList.add(rank);
            if (tempList.size() >= rankNum) {
                break;
            }
        }
        return tempList;
    }

    public int getMyRank(long userId, long serverId) {
        int rank = -1;
        int index = 0;
        synchronized (this) {
            for(EnterNameRank userRank : rankList){
                if(userRank.getUserBaseInfo() == null){
                    continue;
                }
                if(userRank.getUserId() == userId && userRank.getUserBaseInfo().getServerId() == serverId){
                    rank = index + 1;
                    break;
                }
                index++;
            }
        }
        if(rank > rankNum){
            rank = -1;
        }
        return rank;
    }

    public EnterNameRank getMyRankInfo(long userId) {
        synchronized (this) {
            for(EnterNameRank userRank : rankList){
                if(userRank.getUserId() == userId){
                    return userRank;
                }
            }
        }
        return null;
    }

    public int getMyTempRank(long userId, long value){
        int rank = -1;
        XRankProto.XUserRankListMsg temp = listMsg;
        boolean contains = false;
        for (int i = 0; i < temp.getRankListList().size(); i++) {
            XRankProto.XUserRankMsg user = temp.getRankListList().get(i);
            if(user.getUserId() == userId){
                contains = true;
            }
            if(value > new BigInteger(user.getValue()).longValue()){
                if(i == 0){
                    rank = 1;
                }else if(contains){
                    rank = i;
                }else {
                    rank = i + 1;
                }
                break;
            }
        }
        if(rank > rankNum){
            rank = -1;
        }
        if(rank == -1 && temp.getRankListList().size() < rankNum){
            if(contains){
                rank = temp.getRankListList().size();
            }else {
                rank = temp.getRankListList().size() + 1;
            }
        }
        return rank;
    }

    public void initListMsg(){
        XRankProto.XUserRankListMsg.Builder builder = XRankProto.XUserRankListMsg.newBuilder();
        LinkedList<EnterNameRank> list = rankList;
        for (int i = 0; i < list.size() && i < rankNum; i++) {
            EnterNameRank rank = list.get(i);
            if(rank.getUserBaseInfo() == null){
                continue;
            }
            XRankProto.XUserRankMsg.Builder rankBuilder =  ChannelEnterNameRankMgr.buildRankMsg(rank);
            builder.addRankList(rankBuilder);
        }
        builder.setActivityId(activityId);
        builder.setConditionType(conditionType);
        this.listMsg = builder.build();
    }

    public int getMatchGroupId() {
        return matchGroupId;
    }

    public void setMatchGroupId(int matchGroupId) {
        this.matchGroupId = matchGroupId;
    }

    public boolean isSave() {
        return save;
    }

    public void setSave(boolean save) {
        this.save = save;
    }

    public int getActivityId() {
        return activityId;
    }

    public int getConditionType() {
        return conditionType;
    }


}
